import json
import logging
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional
from sqlmodel import Session, select, func
from ..models import Rate
from ..notifier.dingtalk import DingTalkNotifier

logger = logging.getLogger(__name__)


class PolicyEvaluator:
    """策略评估器"""
    
    def __init__(self, session: Session, policy_file: str = "backend/policies/PolicyProfile.json"):
        self.session = session
        self.policy_file = policy_file
        self.policies = self._load_policies()
        self.notifier = DingTalkNotifier(self.policies.get("webhook", ""))
        self.last_notify_times = {}  # 节流控制
    
    def _load_policies(self) -> Dict[str, Any]:
        """加载策略配置"""
        try:
            with open(self.policy_file, 'r', encoding='utf-8') as f:
                policies = json.load(f)
            logger.info(f"加载策略配置成功，共 {len(policies.get('rules', []))} 条规则")
            return policies
        except Exception as e:
            logger.error(f"加载策略配置失败: {e}")
            return {"version": 1, "webhook": "", "rules": []}
    
    def _get_latest_rates(self) -> Dict[str, float]:
        """获取最新汇率"""
        try:
            # 获取最新的CNY和USD汇率
            cny_stmt = select(Rate).where(Rate.quote == "CNY").order_by(Rate.ts_utc.desc()).limit(1)
            usd_stmt = select(Rate).where(Rate.quote == "USD").order_by(Rate.ts_utc.desc()).limit(1)
            
            cny_rate = self.session.exec(cny_stmt).first()
            usd_rate = self.session.exec(usd_stmt).first()
            
            result = {}
            if cny_rate:
                result["JPY_CNY"] = cny_rate.rate
            if usd_rate:
                result["JPY_USD"] = usd_rate.rate
                
            return result
        except Exception as e:
            logger.error(f"获取最新汇率失败: {e}")
            return {}
    
    def _get_daily_change(self, quote: str, lookback_days: int = 1) -> Optional[float]:
        """计算日涨跌幅"""
        try:
            # 获取今天和昨天的汇率
            today = datetime.now().date()
            yesterday = today - timedelta(days=lookback_days)
            
            # 获取今天的汇率（取最新的一条）
            today_stmt = select(Rate).where(
                Rate.quote == quote,
                func.date(Rate.ts_utc) == today
            ).order_by(Rate.ts_utc.desc()).limit(1)
            
            # 获取昨天的汇率（取最新的一条）
            yesterday_stmt = select(Rate).where(
                Rate.quote == quote,
                func.date(Rate.ts_utc) == yesterday
            ).order_by(Rate.ts_utc.desc()).limit(1)
            
            today_rate = self.session.exec(today_stmt).first()
            yesterday_rate = self.session.exec(yesterday_stmt).first()
            
            if today_rate and yesterday_rate:
                change_pct = (today_rate.rate - yesterday_rate.rate) / yesterday_rate.rate
                return change_pct
            
            return None
        except Exception as e:
            logger.error(f"计算 {quote} 日涨跌幅失败: {e}")
            return None
    
    def _should_throttle(self, rule_id: str, throttle_minutes: int) -> bool:
        """检查是否需要节流"""
        now = datetime.now()
        last_time = self.last_notify_times.get(rule_id)
        
        if last_time is None:
            return False
        
        time_diff = (now - last_time).total_seconds() / 60
        return time_diff < throttle_minutes
    
    def _update_throttle_time(self, rule_id: str):
        """更新节流时间"""
        self.last_notify_times[rule_id] = datetime.now()
    
    async def evaluate_rule(self, rule: Dict[str, Any]) -> bool:
        """评估单个规则"""
        try:
            rule_id = rule.get("id", "")
            description = rule.get("description", "")
            left = rule.get("left", {})
            op = rule.get("op", "")
            right = rule.get("right", 0)
            window = rule.get("window")
            notify = rule.get("notify", {})
            
            # 检查节流
            throttle_minutes = notify.get("throttleMinutes", 60)
            if self._should_throttle(rule_id, throttle_minutes):
                logger.debug(f"规则 {rule_id} 在节流期内，跳过")
                return False
            
            # 获取左值
            metric = left.get("metric", "")
            transform = left.get("transform", "")
            
            if metric == "JPY_CNY":
                quote = "CNY"
            elif metric == "JPY_USD":
                quote = "USD"
            else:
                logger.warning(f"未知的指标: {metric}")
                return False
            
            # 计算左值
            left_value = None
            if transform == "rate_or_amount1000":
                latest_rates = self._get_latest_rates()
                rate = latest_rates.get(metric)
                if rate is not None:
                    left_value = rate * 1000  # 1000日元折算
            elif transform == "pct_change_1d":
                lookback_days = window.get("lookbackDays", 1) if window else 1
                left_value = self._get_daily_change(quote, lookback_days)
                if left_value is not None:
                    left_value = left_value  # 已经是百分比
            else:
                logger.warning(f"未知的变换: {transform}")
                return False
            
            if left_value is None:
                logger.warning(f"无法计算左值: {metric} {transform}")
                return False
            
            # 评估条件
            triggered = False
            if op == ">":
                triggered = left_value > right
            elif op == "<":
                triggered = left_value < right
            elif op == ">=":
                triggered = left_value >= right
            elif op == "<=":
                triggered = left_value <= right
            elif op == "==":
                triggered = abs(left_value - right) < 1e-6
            else:
                logger.warning(f"未知的操作符: {op}")
                return False
            
            if triggered:
                logger.info(f"规则 {rule_id} 触发: {description}")
                logger.info(f"  左值: {left_value}, 操作符: {op}, 右值: {right}")
                
                # 发送通知
                latest_rates = self._get_latest_rates()
                jpy_cny = latest_rates.get("JPY_CNY", 0)
                jpy_usd = latest_rates.get("JPY_USD", 0)
                
                change_pct = None
                if transform == "pct_change_1d":
                    change_pct = left_value
                
                success = await self.notifier.send_rate_alert(
                    rule_id, description, jpy_cny, jpy_usd, change_pct
                )
                
                if success:
                    self._update_throttle_time(rule_id)
                    return True
                else:
                    logger.error(f"发送通知失败: {rule_id}")
                    return False
            
            return False
            
        except Exception as e:
            logger.error(f"评估规则失败 {rule.get('id', 'unknown')}: {e}")
            return False
    
    async def evaluate_all_rules(self) -> int:
        """评估所有规则"""
        rules = self.policies.get("rules", [])
        triggered_count = 0
        
        logger.info(f"开始评估 {len(rules)} 条策略规则")
        
        for rule in rules:
            try:
                if await self.evaluate_rule(rule):
                    triggered_count += 1
            except Exception as e:
                logger.error(f"评估规则异常: {e}")
                continue
        
        logger.info(f"策略评估完成，触发 {triggered_count} 条规则")
        return triggered_count
